package website.seamonster.ethegg.schedule;

import org.hibernate.exception.DataException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.DefaultBlockParameterNumber;
import org.web3j.protocol.core.methods.request.EthFilter;
import org.web3j.protocol.core.methods.response.EthLog;
import org.web3j.protocol.http.HttpService;
import org.web3j.tx.ClientTransactionManager;
import org.web3j.tx.RawTransactionManager;
import org.web3j.tx.gas.DefaultGasProvider;
import org.web3j.utils.Convert;
import website.seamonster.ethegg.conf.SystemConfig;
import website.seamonster.ethegg.contracts.EthEggTx_sol_EthEggTx;
import website.seamonster.ethegg.dataobject.DebugBuy;
import website.seamonster.ethegg.dataobject.Msg;
import website.seamonster.ethegg.enums.MsgTypeEnum;
import website.seamonster.ethegg.repository.DebugBuyRepository;
import website.seamonster.ethegg.service.MsgService;
import website.seamonster.ethegg.service.TxReqService;
import website.seamonster.ethegg.utils.MyHexUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Created by 罗海量
 * 2018-07-28 12:03
 */
@lombok.extern.slf4j.Slf4j
@Service
public class ScheduleTimer implements InitializingBean {
    @Autowired
    private TxReqService txReqService;
    @Autowired
    private MsgService msgService;
    @Autowired
    private DebugBuyRepository debugBuyRepository;

    @Value("${contract.node-url}")
    private String nodeUrl;
    @Value("${contract.owner}")
    private String ownerAccount;
    @Value("${contract.address}")
    private String contractAddress;

    private String topicMsg = "0x1c2e8231879486a5c901d464b38b4408600821576ddb11fd776edbdf27cc17a8";

    private String topicDebugBuy = "0x3e174660ed05de5cc370204c635090fa74547abab48d6f2908fe48aba4520268";

    private Web3j web3j;

    @Override
    public void afterPropertiesSet() throws Exception {
        web3j = Web3j.build(new HttpService(nodeUrl));

        ScheduleManager.singleScheduleService.scheduleAtFixedRate(()->{
            try {
                Long _startBlockNum = msgService.getNextBlockNum();
                BigInteger startBlock;
                if (_startBlockNum.equals(0L)){
                    BigInteger blockNumber = web3j.ethBlockNumber().send().getBlockNumber();
                    BigInteger getBlockNum = BigInteger.valueOf(10000L);
                    startBlock = blockNumber.compareTo(getBlockNum)>=0?blockNumber.subtract(getBlockNum):blockNumber;
                } else {
                    startBlock = BigInteger.valueOf(_startBlockNum);
                }

                EthFilter filter = new EthFilter(new DefaultBlockParameterNumber(startBlock), DefaultBlockParameterName.LATEST, contractAddress);
                List<EthLog.LogResult> logs = web3j.ethGetLogs(filter).send().getLogs();

                List<Msg> msgList = logs.stream()
                        .filter(logResult -> {
                            return topicMsg.equals(((EthLog.LogObject)logResult).getTopics().get(0));
                        })
                        .map(logResult -> {
                    String data = ((EthLog.LogObject)logResult).getData();
                    BigInteger blockNum = ((EthLog.LogObject)logResult).getBlockNumber();
                    String data_1 = data.substring(2);
                    String strAccount = data_1.substring(0,64);
                    String strBalance = data_1.substring(64, 128);
                    String strSomeVal = data_1.substring(128, 192);
                    String strMsgType = data_1.substring(192, 256);
                    String strMsgTime = data_1.substring(256);
                    BigInteger biAccount = new BigInteger(strAccount, 16);
                    BigInteger biBalance = new BigInteger(strBalance, 16);
                    BigInteger biSomeVal = new BigInteger(strSomeVal, 16);
                    BigInteger biMsgType = new BigInteger(strMsgType, 16);
                    BigInteger biMsgTime = new BigInteger(strMsgTime, 16);

                    String userId = MyHexUtils.convertToAddressString(biAccount);
                    BigDecimal balance = Convert.fromWei(biBalance.toString(), Convert.Unit.ETHER);
                    BigDecimal someVal = new BigDecimal(biSomeVal.toString());
                    MsgTypeEnum[] values = MsgTypeEnum.values();
                    MsgTypeEnum msgType = values[biMsgType.intValue()];
                    Timestamp createTime = new Timestamp(biMsgTime.longValue()*1000);

                    Msg msg = new Msg();
                    msg.setBlockNum(blockNum.longValue());
                    msg.setCreateTime(createTime);
                    msg.setMsgType(msgType.getCode());
                    msg.setIncome(balance);
                    msg.setSomeVal(someVal);
                    msg.setUserId(userId);
                    return msg;
                }).collect(Collectors.toList());
                msgService.createMsgs(msgList);

                List<DebugBuy> debugBuyList = logs.stream()
                        .filter(logResult -> {
                            return topicDebugBuy.equals(((EthLog.LogObject)logResult).getTopics().get(0));
                        }).map(logResult -> {
                            String data = ((EthLog.LogObject)logResult).getData();
                            String txHash = ((EthLog.LogObject)logResult).getTransactionHash();
                            BigInteger blockNum = ((EthLog.LogObject)logResult).getBlockNumber();

                            String data_1 = data.substring(2);
                            String strTo = data_1.substring(0,64);
                            String strFrom = data_1.substring(64, 128);
                            String strAmt = data_1.substring(128, 192);
                            String strEggId = data_1.substring(192, 256);
                            String strEggStatus = data_1.substring(256, 320);
                            String strChickenId = data_1.substring(320);

                            BigInteger biTo = new BigInteger(strTo, 16);
                            BigInteger biFrom = new BigInteger(strFrom, 16);
                            BigInteger biAmt = new BigInteger(strAmt, 16);
                            BigInteger biEggId = new BigInteger(strEggId, 16);
                            BigInteger biEggStatus = new BigInteger(strEggStatus, 16);
                            BigInteger biChickenId = new BigInteger(strChickenId, 16);

                            String to = MyHexUtils.convertToAddressString(biTo);
                            String from = MyHexUtils.convertToAddressString(biFrom);
                            BigDecimal amt = Convert.fromWei(biAmt.toString(), Convert.Unit.ETHER);
                            Long eggId = biEggId.longValue();
                            Integer eggStatus = biEggStatus.intValue();
                            Long chickenId = biChickenId.longValue();

                            DebugBuy debugBuy = new DebugBuy();
                            debugBuy.setBlockNum(blockNum.longValue());
                            debugBuy.setToAddress(to);
                            debugBuy.setFromAddress(from);
                            debugBuy.setAmt(amt);
                            debugBuy.setEggId(eggId);
                            debugBuy.setEggStatus(eggStatus);
                            debugBuy.setChickenId(chickenId);
                            debugBuy.setTxHash(txHash);
                            return debugBuy;
                        }).collect(Collectors.toList());

                if (debugBuyList != null){
                    debugBuyList.forEach(debugBuy -> {
                        debugBuyRepository.save(debugBuy);
                    });
                }


            }catch (RuntimeException e){
                // TO NOTHING
                log.error("[Runtime Exception] create message error", e.getMessage());
            }catch (Exception e){
                // TO NOTHING
                log.error("[Exception] create message error", e.getMessage());
            }
        }, SystemConfig.CHECK_BLOCK_PER_MILLSECONDS, SystemConfig.CHECK_BLOCK_PER_MILLSECONDS, TimeUnit.MILLISECONDS);


    }
}
